package com.zxmr.asyn;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TaskMonitor implements Runnable{

	private volatile DelayQueue<RequestTimeoutDelayed> queue =
										new DelayQueue<RequestTimeoutDelayed>();
	public ExecutorService  worker = null;
	public final int minThreadNum;
	public final int maxThreadNum;
	public final long threadFreeTime = 30L;
	public final int threadBlockQueueSize = 500;
    public TaskMonitor(int minThreadNum,int maxThreadNum){
    	this.minThreadNum = minThreadNum;
    	this.maxThreadNum = maxThreadNum;
    	
		worker = new ThreadPoolExecutor(minThreadNum,maxThreadNum,threadFreeTime,TimeUnit.SECONDS,
						new ArrayBlockingQueue<Runnable>(threadBlockQueueSize),
							new ThreadPoolExecutor.CallerRunsPolicy());

    }
	public void run() {
		while (true) {
			try {
				
				RequestTimeoutDelayed delay = queue.take();
				delay.process();
			}catch(InterruptedException e)
			{
				break;
			}catch (Exception ex) {
				ex.printStackTrace();

			}
		}
	}
    public void addTask(MonitorCallBack task, long timeout) {
        queue.put(new RequestTimeoutDelayed(task, timeout));
    }
    class RequestTimeoutDelayed implements Delayed {
		private MonitorCallBack task;
		private long joinQueueTime;
		private long timeout;
		
		public RequestTimeoutDelayed(MonitorCallBack task,long timeout) {
			this.task = task;
			this.joinQueueTime = System.currentTimeMillis();
			this.timeout = timeout;
		}
        
		public void process() {

			try
			{
				task.process(worker);
				 
			}catch(RuntimeException e)
			{
				e.printStackTrace();
			}
           
		}

		public long getDelay(TimeUnit unit) {
		       return unit.convert((this.joinQueueTime + this.timeout) -
                       System.currentTimeMillis(),
                       TimeUnit.MILLISECONDS);
		}

		public int compareTo(Delayed obj) {
			// TODO Auto-generated method stub
            if (obj == this) {
                return 0;
            } else if (obj instanceof RequestTimeoutDelayed) {
            	RequestTimeoutDelayed x    = (RequestTimeoutDelayed) obj;
                long  diff = (this.timeout - x.timeout) +
                                      (this.joinQueueTime - x.joinQueueTime);

                return (diff < 0) ? -1
                                  : ((diff > 0) ? (1)
                                                : ((this.joinQueueTime > x.joinQueueTime)
                                                   ? 1 : (-1)));
            } else {
                long interval = this.getDelay(TimeUnit.MILLISECONDS) -obj.getDelay(TimeUnit.MILLISECONDS);

                return (interval == 0) ? 0 : ((interval > 0) ? 1 : (-1));
            }
		}
		
	}
}
